package com.example.mysql.log;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileMode;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.mysql.HaInnodb;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

/**
 * wzy:wzynov@qq.com
 */
public class RedoLogUtil {

    public static String REDO_LOG_FILE = "ib_logfile";

    public static void createLogFile() {
        if (!FileUtil.exist(Paths.get(REDO_LOG_FILE).toFile())) {
            FileUtil.createRandomAccessFile(Paths.get(REDO_LOG_FILE), FileMode.rw);

            try (BufferedWriter writer = FileUtil.getWriter(Paths.get(REDO_LOG_FILE).toFile(), StandardCharsets.UTF_8, true)) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.putIfAbsent("checkpointLsn", 0);
                String jsonStr = JSONUtil.toJsonStr(jsonObject);
                writer.write(jsonStr);
                writer.newLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void appendRedoLog(Integer trxId, RedoLog redoLog) {
        List<RedoLog> redoLogList = HaInnodb.logBuffer.get(trxId);
        if (CollUtil.isEmpty(redoLogList)) {
            redoLogList = new ArrayList<>();
        }
        redoLogList.add(redoLog);
        HaInnodb.logBuffer.put(trxId, redoLogList);
    }

    /**
     * 事务提交时执行
     * @param trxId 事务id
     */
    public static void persistRedoLog(Integer trxId) {
        List<RedoLog> redoLogList = HaInnodb.logBuffer.get(trxId);

        try (BufferedWriter writer = FileUtil.getWriter(Paths.get(REDO_LOG_FILE).toFile(), StandardCharsets.UTF_8, true)) {
            for (RedoLog redoLog : redoLogList) {
                String jsonStr = JSONUtil.toJsonStr(redoLog);
                writer.write(jsonStr);
                writer.newLine();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static int writeCheckpointLsn(int maxCheckpointLsn) {
        try(BufferedReader reader = FileUtil.getUtf8Reader(Paths.get(REDO_LOG_FILE).toFile())) {
            String header = reader.readLine();
            JSONObject jsonObject = JSONUtil.parseObj(header);
            jsonObject.set("checkpointLsn", maxCheckpointLsn);

            try (FileChannel fileChannel = FileChannel.open(Paths.get(REDO_LOG_FILE), StandardOpenOption.WRITE)) {
                fileChannel.position(0);
                return fileChannel.write(ByteBuffer.wrap(JSONUtil.toJsonStr(jsonObject).getBytes(StandardCharsets.UTF_8)));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
